package com.freeLearning.boot.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.freeLearning.boot.common.constant.RedisConstants;
import com.freeLearning.boot.common.constant.SystemConstants;
import com.freeLearning.boot.shared.auth.service.TokenService;
import com.freeLearning.boot.shared.file.service.FileService;
import com.freeLearning.boot.common.enums.AuditStatusEnum;
import com.freeLearning.boot.system.enums.ContactType;
import com.freeLearning.boot.common.model.Option;
import com.freeLearning.boot.shared.mail.service.MailService;
import com.freeLearning.boot.shared.sms.service.SmsService;
import com.freeLearning.boot.system.enums.DocumentsTypeEnum;
import com.freeLearning.boot.system.enums.MessageEnum;
import com.freeLearning.boot.system.mapper.ConsultantAuditHistoryMapper;
import com.freeLearning.boot.system.mapper.ConsultantAuditMapper;
import com.freeLearning.boot.system.mapper.UserExpertiseMapper;
import com.freeLearning.boot.system.model.bo.FileBO;
import com.freeLearning.boot.system.model.bo.UserExpertiseBO;
import com.freeLearning.boot.system.model.entity.*;
import com.freeLearning.boot.system.model.form.*;
import com.freeLearning.boot.config.property.AliyunSmsProperties;
import com.freeLearning.boot.system.converter.UserConverter;
import com.freeLearning.boot.common.exception.BusinessException;
import com.freeLearning.boot.system.model.vo.DocumentsVO;
import com.freeLearning.boot.system.model.vo.UserProfileVO;
import com.freeLearning.boot.core.security.util.SecurityUtils;
import com.freeLearning.boot.system.mapper.UserMapper;
import com.freeLearning.boot.system.model.dto.UserAuthInfo;
import com.freeLearning.boot.system.model.bo.UserBO;
import com.freeLearning.boot.system.model.query.UserPageQuery;
import com.freeLearning.boot.system.model.dto.UserExportDTO;
import com.freeLearning.boot.system.model.vo.UserInfoVO;
import com.freeLearning.boot.system.model.vo.UserPageVO;
import com.freeLearning.boot.core.security.service.PermissionService;
import com.freeLearning.boot.system.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.freeLearning.boot.common.constant.SystemConstants.AUDIT_DEFAULT_MESSAGE;

/**
 * 用户业务实现类
 *
 * @author haoxr
 * @since 2022/1/14
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final PasswordEncoder passwordEncoder;

    private final UserRoleService userRoleService;

    private final RoleMenuService roleMenuService;

    private final RoleService roleService;

    private final PermissionService permissionService;

    private final SmsService smsService;

    private final MailService mailService;

    private final AliyunSmsProperties aliyunSmsProperties;

    private final StringRedisTemplate redisTemplate;

    private final TokenService tokenService;

    private final UserConverter userConverter;

    private final UserExpertiseMapper userExpertiseMapper;

    private final ConsultantDocumentService consultantDocumentService;

    private final ConsultantAuditMapper consultantAuditMapper;
    private final ConsultantAuditHistoryMapper consultantAuditHistoryMapper;
    private final ConsultantAuditService consultantAuditService;
    private final FileService fileService;
    private final MessageService messageService;

    /**
     * 获取用户分页列表
     *
     * @param queryParams 查询参数
     * @return {@link IPage<UserPageVO>} 用户分页列表
     */
    @Override
    public IPage<UserPageVO> getUserPage(UserPageQuery queryParams) {

        // 参数构建
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        Page<UserBO> page = new Page<>(pageNum, pageSize);
        // 查询数据
        Page<UserBO> userPage = this.baseMapper.getUserPage(page, queryParams);
        List<UserBO> list = userPage.getRecords().stream().peek(item->{
            List<UserExpertiseBO> ub = this.userExpertiseMapper.getUserExpertise(item.getId());
            item.setExpertiseList(ub);
        }).toList();
        userPage.setRecords(list);

        // 实体转换
        return userConverter.toPageVo(userPage);
    }

    /**
     * 获取用户表单数据
     *
     * @param userId 用户ID
     * @return
     */
    @Override
    public UserForm getUserFormData(Long userId) {
        UserForm uf = this.baseMapper.getUserFormData(userId);
        List<UserExpertiseBO> userExpertise = userExpertiseMapper.getUserExpertise(userId);
        uf.setExpertiseList(userExpertise.stream().map(UserExpertiseBO::getExpertiseCode).toList());
        return setVODocuments(userId, uf);
    }

    /**
     * 新增用户
     *
     * @param userForm 用户表单对象
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveUser(UserForm userForm) {

        String username = userForm.getUsername();

        long count = this.count(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        Assert.isTrue(count == 0, "用户名已存在");
        long mobile = this.count(new LambdaQueryWrapper<User>().eq(User::getMobile, userForm.getMobile()));
        Assert.isTrue(mobile == 0, "手机号已存在");
        long emailNum = this.count(new LambdaQueryWrapper<User>().eq(User::getEmail, userForm.getEmail()));
        Assert.isTrue(emailNum == 0, "邮箱已存在");
        // 实体转换 form->entity
        User entity = userConverter.toEntity(userForm);
        if (!userForm.getEmailCode().isEmpty()){
            String inputVerificationCode = userForm.getEmailCode();
            String email = userForm.getEmail();

            String redisCacheKey = RedisConstants.EMAIL_VERIFICATION_CODE_PREFIX + email;
            String cachedVerificationCode = redisTemplate.opsForValue().get(redisCacheKey);

            if (!inputVerificationCode.equals(cachedVerificationCode)) {
                throw new BusinessException("验证码错误");
            }
        }

        // 设置默认加密密码
        if (userForm.getPassword() == null) {
            String idCard = userForm.getIdCard();
            String defaultPassword = idCard.substring(idCard.length()-6);
            // 截取身份证后 6 位
            String defaultEncryptPwd = passwordEncoder.encode(defaultPassword);
            entity.setPassword(defaultEncryptPwd);
        }else{
            entity.setPassword(passwordEncoder.encode(userForm.getPassword()));
        }
        // 新增用户
        boolean result = this.save(entity);

        if (result) {
            if (userForm.getExpertiseList()!=null && !userForm.getExpertiseList().isEmpty()){
                userExpertiseMapper.insertExpertise(entity.getId(),userForm.getExpertiseCodes());
            }
            // 保存用户角色
            userRoleService.saveUserRoles(entity.getId(), userForm.getRoleIds());
            this.saveConsultantDocument(userForm,entity.getId());
            if (userForm.getIsConsultant() != null && userForm.getIsConsultant()){
                ConsultantAudit consultantAudit = new ConsultantAudit();
                consultantAudit.setConsultantId(entity.getId());
                consultantAudit.setAuditorId(entity.getId());
                consultantAudit.setOpinion("正在审核中");
                consultantAuditMapper.insert(consultantAudit);
                ConsultantAuditHistory consultantAuditHistory = BeanUtil.copyProperties(consultantAudit, ConsultantAuditHistory.class);
                consultantAuditHistory.setId(null);
                consultantAuditHistory.setStatus(0);
                consultantAuditHistoryMapper.insert(consultantAuditHistory);
                userRoleService.list(new LambdaQueryWrapper<UserRole>().eq(UserRole::getRoleId, 2)).forEach(item->{
                    Message message = Message.builder()
                            .title("有新的咨询师注册啦")
                            .content(userForm.getNickname()+"注册了我们平台的咨询师，请尽快审核！")
                            .type(MessageEnum.INFO_AUDIT.getValue())
                            .publisherId(entity.getId())
                            .publishTime(LocalDateTime.now())
                            .createBy(entity.getId())
                            .other(JSONUtil.toJsonStr(userForm))
                            .acceptId(item.getUserId())
                            .build();
                    messageService.sendMessage(message);
                });
                String idCard = userForm.getIdCard();
                String defaultPassword = idCard.substring(idCard.length()-6);
                mailService.sendHTMLMail(
                        entity.getEmail(),
                        "恭喜您注册成功",
                        getConsultantRegistrationSuccessMailContent(entity.getUsername(),defaultPassword),
                        false
                );
            }

        }
        return result;
    }

    public void saveConsultantDocument(UserForm userForm, Long userId){
        ConsultantDocument consultantDocument = new ConsultantDocument();
        consultantDocument.setConsultantId(userId);
        if (userForm.getIdCardFrontUrl() != null && !userForm.getIdCardFrontUrl().isEmpty()){
            consultantDocument.setDocumentType(DocumentsTypeEnum.ID_CARD_FRONT);
            consultantDocument.setDocumentUrl(userForm.getIdCardFrontUrl());
            consultantDocument.setFileName(userForm.getNickname()+DocumentsTypeEnum.ID_CARD_FRONT.getLabel());
            consultantDocumentService.save(consultantDocument);
        }
        if (userForm.getIdCardBackUrl() != null && !userForm.getIdCardBackUrl().isEmpty()){
            consultantDocument.setDocumentType(DocumentsTypeEnum.ID_CARD_BACK);
            consultantDocument.setDocumentUrl(userForm.getIdCardBackUrl());
            consultantDocument.setFileName(userForm.getNickname()+DocumentsTypeEnum.ID_CARD_BACK.getLabel());
            consultantDocumentService.save(consultantDocument);
        }
        if (userForm.getDegreeUrl() != null && !userForm.getDegreeUrl().isEmpty()){
            consultantDocument.setDocumentType(DocumentsTypeEnum.DEGREE);
            consultantDocument.setDocumentUrl(userForm.getDegreeUrl());
            consultantDocument.setFileName(userForm.getNickname()+DocumentsTypeEnum.DEGREE.getLabel());
            consultantDocumentService.save(consultantDocument);
        }
        if (userForm.getOtherUrl() != null && !userForm.getOtherUrl().isEmpty()){
            for (FileBO file : userForm.getOtherUrl()) {
                consultantDocument.setDocumentType(DocumentsTypeEnum.OTHER);
                consultantDocument.setDocumentUrl(file.getUrl());
                consultantDocument.setFileName(file.getFileName());
                consultantDocumentService.save(consultantDocument);
            }
        }
    }
    /**
     * 更新用户
     *
     * @param userId   用户ID
     * @param userForm 用户表单对象
     * @return
     */
    @Override
    @Transactional
    public boolean updateUser(Long userId, UserForm userForm) {

        String username = userForm.getUsername();

        long count = this.count(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username)
                .ne(User::getId, userId)
        );
        Assert.isTrue(count == 0, "用户名已存在");

        // form -> entity
        User entity = userConverter.toEntity(userForm);

        // 修改用户
        boolean result = this.updateById(entity);

        if (result) {
            userExpertiseMapper.deleteExpertiseByUserId(userId);
            if (userForm.getExpertiseList()!=null && !userForm.getExpertiseList().isEmpty()){
                userExpertiseMapper.insertExpertise(userId,userForm.getExpertiseCodes());
            }
            // 保存用户角色
            userRoleService.saveUserRoles(entity.getId(), userForm.getRoleIds());
            consultantDocumentService.remove(new QueryWrapper<ConsultantDocument>().eq("consultant_id", userId));
            this.saveConsultantDocument(userForm,entity.getId());
            ConsultantAudit consultantAudit = consultantAuditService.getOne(new QueryWrapper<ConsultantAudit>().eq("consultant_id", userId));
            consultantAudit.setStatus(AuditStatusEnum.WAIT_AUDIT.getValue());
            consultantAudit.setOpinion(AUDIT_DEFAULT_MESSAGE);
            consultantAudit.setAuditTime(LocalDateTime.now());
            consultantAuditService.updateById(consultantAudit);
            ConsultantAuditHistory consultantAuditHistory = BeanUtil.copyProperties(consultantAudit, ConsultantAuditHistory.class);
            consultantAuditHistory.setId(null);
            consultantAuditHistoryMapper.insert(consultantAuditHistory);
            userRoleService.list(new LambdaQueryWrapper<UserRole>().eq(UserRole::getRoleId, 2)).forEach(item->{
                Message message = Message.builder()
                        .title("咨询师的信息发生变化,请尽快审核")
                        .content("咨询师："+userForm.getNickname()+"的身份信息发生变化，请尽快审核！")
                        .type(MessageEnum.INFO_AUDIT.getValue())
                        .publisherId(entity.getId())
                        .publishTime(LocalDateTime.now())
                        .createBy(entity.getId())
                        .other(JSONUtil.toJsonStr(userForm))
                        .acceptId(item.getUserId())
                        .build();
                messageService.sendMessage(message);
            });
        }
        return result;
    }

    /**
     * 删除用户
     *
     * @param idsStr 用户ID，多个以英文逗号(,)分割
     * @return true|false
     */
    @Override
    public boolean deleteUsers(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "删除的用户数据为空");
        // 逻辑删除
        List<Long> ids = Arrays.stream(idsStr.split(","))
                .map(Long::parseLong)
                .collect(Collectors.toList());
        return this.removeByIds(ids);

    }

    /**
     * 根据用户名获取认证信息
     *
     * @param username 用户名
     * @return 用户认证信息 {@link UserAuthInfo}
     */
    @Override
    public UserAuthInfo getUserAuthInfo(String username) {
        UserAuthInfo userAuthInfo = this.baseMapper.getUserAuthInfo(username);
        if (userAuthInfo != null) {
            Set<String> roles = userAuthInfo.getRoles();
            // 获取最大范围的数据权限
            Integer dataScope = roleService.getMaximumDataScope(roles);
            userAuthInfo.setDataScope(dataScope);
        }
        return userAuthInfo;
    }


    /**
     * 根据 openid 获取用户认证信息
     *
     * @param openid 微信
     * @return {@link UserAuthInfo}
     */
    @Override
    public UserAuthInfo getUserAuthInfoByOpenId(String openid) {
        UserAuthInfo userAuthInfo = this.baseMapper.getUserAuthInfoByOpenId(openid);
        if (userAuthInfo != null) {
            Set<String> roles = userAuthInfo.getRoles();
            // 获取最大范围的数据权限
            Integer dataScope = roleService.getMaximumDataScope(roles);
            userAuthInfo.setDataScope(dataScope);
        }
        return userAuthInfo;
    }

    /**
     * 根据微信 OpenID 注册或绑定用户
     * <p>
     * TODO 根据手机号绑定用户
     *
     * @param openId 微信 OpenID
     */
    @Override
    public void registerOrBindWechatUser(String openId) {
        User user = this.getOne(
                new LambdaQueryWrapper<User>().eq(User::getOpenid, openId)
        );
        if (user == null) {
            user = new User();
            user.setNickname("微信用户");  // 默认昵称
            user.setUsername(openId);      // TODO 后续替换为手机号
            user.setOpenid(openId);
            user.setGender(0); // 保密
            user.setUpdateBy(SecurityUtils.getUserId());
            user.setPassword(SystemConstants.DEFAULT_PASSWORD);
            this.save(user);
            // 为了默认系统管理员角色，这里按需调整，实际情况绑定已存在的系统用户，另一种情况是给默认游客角色，然后由系统管理员设置用户的角色
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(1L);  // TODO 系统管理员
            userRoleService.save(userRole);
        }
    }

    /**
     * 获取导出用户列表
     *
     * @param queryParams 查询参数
     * @return {@link List<UserExportDTO>} 导出用户列表
     */
    @Override
    public List<UserExportDTO> listExportUsers(UserPageQuery queryParams) {
        return this.baseMapper.listExportUsers(queryParams);
    }

    /**
     * 获取登录用户信息
     *
     * @return {@link UserInfoVO}   用户信息
     */
    @Override
    public UserInfoVO getCurrentUserInfo() {

        String username = SecurityUtils.getUsername();

        // 获取登录用户基础信息
        User user = this.getOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username)
                .select(
                        User::getId,
                        User::getUsername,
                        User::getNickname,
                        User::getAvatar,
                        User::getIsUpdatePassword
                )
        );
        // entity->VO
        UserInfoVO userInfoVO = userConverter.toUserInfoVo(user);

        // 用户角色集合
        Set<String> roles = SecurityUtils.getRoles();
        userInfoVO.setRoles(roles);

        // 用户权限集合
        if (CollectionUtil.isNotEmpty(roles)) {
            Set<String> perms = permissionService.getRolePermsFormCache(roles);
            ConsultantAudit consultantAudit = consultantAuditService.getOne(new QueryWrapper<ConsultantAudit>()
                    .eq("consultant_id", userInfoVO.getUserId()));
            if (consultantAudit != null && consultantAudit.getStatus().equals(AuditStatusEnum.AUDIT_PASS.getValue())) {
                perms.add("sys:course:pass");
            }
            userInfoVO.setPerms(perms);
        }
        return userInfoVO;
    }

    /**
     * 获取个人中心用户信息
     *
     * @param userId 用户ID
     * @return
     */
    @Override
    public UserProfileVO getUserProfile(Long userId) {
        UserBO entity = this.baseMapper.getUserProfile(userId);
        List<UserExpertiseBO> userExpertise = this.userExpertiseMapper.getUserExpertise(userId);
        UserProfileVO profileVO = userConverter.toProfileVO(entity);
        profileVO.setAcademicDegreeCode(entity.getAcademicDegreeCode());
        profileVO.setAcademicDegreeName(entity.getAcademicDegreeName());
        profileVO.setExpertiseList(userExpertise);
        ConsultantAudit consultantAudit = consultantAuditService.getOne(new QueryWrapper<ConsultantAudit>().eq("consultant_id", userId));
        if (consultantAudit != null){
            profileVO.setAuditorId(consultantAudit.getAuditorId());
            profileVO.setAuditorName(consultantAudit.getAuditorName());
            profileVO.setAuditStatus(consultantAudit.getStatus());
            profileVO.setAuditTime(consultantAudit.getAuditTime());
            profileVO.setOpinion(consultantAudit.getOpinion());
        }
        profileVO.setIsConsultant(entity.getRoleNames().equals("咨询师"));
        return setVODocuments(userId, profileVO);
    }

    /**
     * 修改个人中心用户信息
     *
     * @param formData 表单数据
     * @return
     */
    @Override
    public boolean updateUserProfile(UserProfileForm formData) {
        Long userId = SecurityUtils.getUserId();
        User entity = userConverter.toEntity(formData);
        entity.setId(userId);
        return this.updateById(entity);
    }

    /**
     * 修改用户密码
     *
     * @param userId 用户ID
     * @param data   密码修改表单数据
     * @return
     */
    @Override
    public boolean changePassword(Long userId, PasswordChangeForm data) {

        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        String oldPassword = data.getOldPassword();

        // 校验原密码
        if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            throw new BusinessException("原密码错误");
        }
        // 新旧密码不能相同
        if (passwordEncoder.matches(data.getNewPassword(), user.getPassword())) {
            throw new BusinessException("新密码不能与原密码相同");
        }

        String newPassword = data.getNewPassword();
        boolean result = this.update(new LambdaUpdateWrapper<User>()
                .eq(User::getId, userId)
                .set(User::getPassword, passwordEncoder.encode(newPassword))
                .set(User::getIsUpdatePassword, 1)
        );

        if (result) {
            // 加入黑名单，重新登录
            String accessToken = SecurityUtils.getTokenFromRequest();
            tokenService.blacklistToken(accessToken);
        }
        return result;
    }

    /**
     * 重置密码
     *
     * @param userId   用户ID
     * @param password 密码重置表单数据
     * @return
     */
    @Override
    public boolean resetPassword(Long userId, String password) {
        String encode = passwordEncoder.encode(password);
        return this.update(new LambdaUpdateWrapper<User>()
                .eq(User::getId, userId)
                .set(User::getPassword, encode)
        );
    }

    /**
     * 发送验证码
     *
     * @param contact 联系方式 手机号/邮箱
     * @param type    联系方式类型 {@link ContactType}
     * @return
     */
    @Override
    public boolean sendVerificationCode(String contact, ContactType type) {

        // 随机生成4位验证码
        String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
        // 发送验证码

        String verificationCodePrefix = null;
        switch (type) {
            case MOBILE:
                // 获取修改密码的模板code
                String changePasswordSmsTemplateCode = aliyunSmsProperties.getTemplateCodes().get("changePassword");
                smsService.sendSms(contact, changePasswordSmsTemplateCode, "[{\"code\":\"" + code + "\"}]");
                verificationCodePrefix = RedisConstants.MOBILE_VERIFICATION_CODE_PREFIX;
                break;
            case EMAIL:
                User user = this.getOne(new LambdaQueryWrapper<User>().eq(User::getEmail, contact));
                if (user != null){
                    throw new BusinessException("邮箱已被绑定");
                }
                mailService.sendHTMLMail(contact, "验证码", getVerificationCodeMailContent(code,5),true);
                verificationCodePrefix = RedisConstants.EMAIL_VERIFICATION_CODE_PREFIX;
                break;
            default:
                throw new BusinessException("不支持的联系方式类型");
        }
        // 存入 redis 用于校验, 5分钟有效
        redisTemplate.opsForValue().set(verificationCodePrefix + contact, code, 5, TimeUnit.MINUTES);
        return true;
    }

    /**
     * 修改当前用户手机号码
     *
     * @param form 表单数据
     * @return
     */
    @Override
    public boolean bindMobile(MobileBindingForm form) {
        Long currentUserId = SecurityUtils.getUserId();
        User currentUser = this.getById(currentUserId);

        if (currentUser == null) {
            throw new BusinessException("用户不存在");
        }

        // 校验验证码
        String inputVerificationCode = form.getCode();
        String mobile = form.getMobile();

        String redisCacheKey = RedisConstants.MOBILE_VERIFICATION_CODE_PREFIX + mobile;
        String cachedVerificationCode = redisTemplate.opsForValue().get(redisCacheKey);

        if (!inputVerificationCode.equals(cachedVerificationCode)) {
            throw new BusinessException("验证码错误");
        }

        // 更新手机号码
        return this.update(
                new LambdaUpdateWrapper<User>()
                        .eq(User::getId, currentUserId)
                        .set(User::getMobile, mobile)
        );
    }

    /**
     * 修改当前用户邮箱
     *
     * @param form 表单数据
     * @return
     */
    @Override
    public boolean bindEmail(EmailBindingForm form) {
        Long currentUserId = SecurityUtils.getUserId();

        User currentUser = this.getById(currentUserId);
        if (currentUser == null) {
            throw new BusinessException("用户不存在");
        }

        // 校验验证码
        String inputVerificationCode = form.getCode();
        String email = form.getEmail();

        String redisCacheKey = RedisConstants.EMAIL_VERIFICATION_CODE_PREFIX + email;
        String cachedVerificationCode = redisTemplate.opsForValue().get(redisCacheKey);

        if (!inputVerificationCode.equals(cachedVerificationCode)) {
            throw new BusinessException("验证码错误");
        }

        // 更新邮箱地址
        return this.update(
                new LambdaUpdateWrapper<User>()
                        .eq(User::getId, currentUserId)
                        .set(User::getEmail, email)
        );
    }

    /**
     * 获取用户选项列表
     *
     * @return {@link List<Option<String>>} 用户选项列表
     */
    @Override
    public List<Option<String>> listUserOptions() {
        List<User> list = this.list();
        if (CollectionUtil.isNotEmpty(list)) {
            return list.stream().map(user -> new Option<>(user.getId().toString(), user.getNickname())).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    @Override
    public List<Option<String>> listConsultantOptions() {
        List<User> list = this.list();

        if (CollectionUtil.isNotEmpty(list)) {
            return list.stream().filter(item -> {
                List<UserRole> userRole = userRoleService.list(new QueryWrapper<UserRole>().eq("user_id", item.getId()).eq("role_id", 13));
                return !userRole.isEmpty();
            }).map(item -> {
                return new Option<>(item.getId().toString(), item.getNickname());
            }).toList();
        }
        return List.of();
    }

    @Override
    public List<UserPageVO> getConsultantList(String expertiseId) {
        List<Long> ids = consultantAuditService.list(new QueryWrapper<ConsultantAudit>()
                        .eq("status", AuditStatusEnum.AUDIT_PASS.getValue()))
                .stream().map(ConsultantAudit::getConsultantId).toList();
        List<User> list = List.of();
        if (!ids.isEmpty()){
            list  = this.list(new QueryWrapper<User>().in("id", ids));
        }
        if (CollectionUtil.isNotEmpty(list)) {
            List<User> consultantList = list.stream().filter(item -> {
                List<UserRole> userRole = userRoleService.list(new QueryWrapper<UserRole>().eq("user_id", item.getId()).eq("role_id", 13));
                return !userRole.isEmpty();
            }).toList();
            List<UserPageVO> vos = consultantList.stream().map(item -> {
                UserPageVO userPageVO = BeanUtil.copyProperties(item, UserPageVO.class);
                userPageVO.setExpertiseList(
                        BeanUtil.copyToList(userExpertiseMapper.getUserExpertise(item.getId()), UserExpertiseBO.class)
                );
                return userPageVO;
            }).toList();
            if (expertiseId.equals("all")){
                return vos;
            }
            return vos.stream().filter(item->{
                // ExpertiseList中是否包含expertiseId
                return item.getExpertiseList().stream()
                        .anyMatch(expertise -> expertise.getExpertiseCode().equals(expertiseId));
            }).toList();
        }
        return List.of();
    }

    private <T extends DocumentsVO> T setVODocuments(Long userId, T VO) {
        List<ConsultantDocument> documents = consultantDocumentService.list(new QueryWrapper<ConsultantDocument>().eq("consultant_id", userId));
        List<FileBO> ortherList = new ArrayList<FileBO >();
        documents.forEach(item->{
            switch (item.getDocumentType()){
                case ID_CARD_FRONT:
                    VO.setIdCardFrontUrl(item.getDocumentUrl());
                    break;
                case ID_CARD_BACK:
                    VO.setIdCardBackUrl(item.getDocumentUrl());
                    break;
                case DEGREE:
                    VO.setDegreeUrl(item.getDocumentUrl());
                    break;
                default:
                    FileBO file = new FileBO();
                    file.setUrl(item.getDocumentUrl());
                    file.setFileName(item.getFileName());
                    ortherList.add(file);
            }
        });
        VO.setOtherUrl(ortherList);
        return VO;
    }
    private String getVerificationCodeMailContent(String code, long expirationTime) {
        StringBuilder content = new StringBuilder();
        content.append("<html><body style='font-family: Arial, sans-serif; background-color: #f4f4f4; padding: 20px;'>");
        content.append("<div style='background-color: #ffffff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);'>");

        // 添加平台Logo和标题
        content.append("<img src='http://www.free-learning.icu/images/logo.png' alt='公益性教育咨询平台' style='width: 150px; height: auto; display: block; margin: 0 auto;'><br>");
        content.append("<h1 style='color: #333333; text-align: center;'>验证码通知</h1>");

        // 用户问候
        content.append("<p style='color: #666666;'>尊敬的用户：</p>");
        content.append("<p style='color: #666666;'>您的验证码如下：</p>");

        // 验证码部分
        content.append("<p style='color: #28a745; font-size: 24px; text-align: center; margin: 20px 0;'>").append(code).append("</p>");

        // 验证码有效期
        content.append("<p style='color: #666666;'>验证码有效期为 ").append(expirationTime).append(" 分钟，请尽快使用。</p>");

        // 安全提示
        content.append("<p style='color: #666666;'>如果您未进行此操作，请忽略此邮件。如果您的账户存在安全风险，请及时联系我们。</p>");

        // 结尾
        content.append("<p style='color: #666666;'>感谢您对 <a href='http://www.free-learning.icu/' style='color: #007bff;'>公益性教育咨询平台</a> 的支持！</p>");
        content.append("<p style='color: #666666;'>祝您学习愉快！</p>");
        content.append("</div>");
        content.append("</body></html>");
        return content.toString();
    }
    private String getConsultantRegistrationSuccessMailContent(String username,String password) {
        StringBuilder content = new StringBuilder();
        content.append("<html><body style='font-family: Arial, sans-serif; background-color: #f4f4f4; padding: 20px;'>");
        content.append("<div style='background-color: #ffffff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);'>");

        // 添加平台Logo和标题
        content.append("<img src='http://www.free-learning.icu/images/logo.png' alt='公益性教育咨询平台' style='width: 150px; height: auto; display: block; margin: 0 auto;'><br>");
        content.append("<h1 style='color: #333333; text-align: center;'>咨询师注册成功通知</h1>");

        // 用户问候
        content.append("<p style='color: #666666;'>尊敬的咨询师：</p>");
        content.append("<p style='color: #666666;'>恭喜您！您已成功注册成为 <a href='http://www.free-learning.icu/' style='color: #007bff;'>公益性教育咨询平台</a> 的咨询师。</p>");

        // 审核说明
        content.append("<p style='color: #666666;'>您的注册信息正在审核中，审核通过后就可以在后台添加课程啦,审核结果将在 <strong style='color: #28a745;'>三日内</strong> 通知您，请耐心等待。</p>");
        content.append("<p style='color: #666666;'>您可以通过以下链接访问后台管理系统，查看注册进度：</p>");
        content.append("<p style='color: #007bff; text-align: center;'><a href='").append("http://www.free-learning.icu:8080/").append("' style='color: #007bff;'>").append("http://www.free-learning.icu:8080/").append("</a></p>");

        // 安全提示
        content.append("<p style='color: #666666;'>登录账号为："+ username+"</p>");
        content.append("<p style='color: #666666;'>登录密码为："+password+"</p>");
        content.append("<p style='color: #666666;'>如果您在注册过程中遇到任何问题，请及时联系我们。</p>");

        // 结尾
        content.append("<p style='color: #666666;'>感谢您加入 <a href='http://www.free-learning.icu/' style='color: #007bff;'>公益性教育咨询平台</a>！</p>");
        content.append("<p style='color: #666666;'>祝您工作顺利！</p>");
        content.append("</div>");
        content.append("</body></html>");
        return content.toString();
    }
}
